import React from 'react'
import Component, { mapStateToProps, mapDispatchToProps } from '@components/Component'
import { connect } from 'react-redux'
import _ from 'loadsh'
import PropTypes from 'prop-types'
import { Button, message, Form, Input, Modal, Alert, Skeleton } from 'antd'
import { ExclamationCircleOutlined } from '@ant-design/icons'
import NextOperatorSelector from './NextOperatorSelector'
import style from './Index.module.less'
import { ApproveBlock, Header, TitleLine, TextLine, TextCell, Split, Line, Cell, Footer, DocLink } from './Approve'
import { updateUncompleteMessage } from '@redux/actions'
import OperateBtns from './OperateBtns'
import moment from 'moment'
const { Item } = Form
const { confirm } = Modal
class ApproveList extends Component {
  state = {
    instances: [],
    instancesMap: {},
    loading: false,
    ready: false,
    currentAction: null,
    currentFlow: null,
    currentFormData: null,
    nextOperators: [],
    nextOperatorSelectorVisible: false,
    nextOperatorId: '',
    creating: false,
    doActioning: false,
    flowName: '',
    startTitle: '新增呈批',
    noFirstNode: true // 所有实例没有处于初始节点的状态
  }

  formRef = {}

  // 初始化获取数据
  getData () {
    const hide = message.loading('获取呈批列表', 120)
    if (this.props.flowKey) {
      this.getDefineByKey(hide)
    } else if (this.props.flowName) {
      this.getFlowInstances(this.props.flowName, hide)
    }
  }

  // 获取呈批定义
  getDefineByKey (hide) {
    this.$get(`/api/vendor/flow/bykey/${this.props.flowKey}`)
      .then(res => {
        if (res.status === 1) {
          this.setState({
            flowName: res.data.name,
            startTitle: res.data.start_title
          }, () => {
            this.getFlowInstances(hide)
          })
        } else {
          hide()
          message.warning(res.message)
        }
      }).catch(() => hide())
  }

  // 重置所有form表单
  resetAllForm () {
    const keys = Object.keys(this.formRef)
    keys.forEach(key => {
      const c = this.formRef[key].current
      if (c) {
        c.resetFields()
      }
    })
  }

  // 获取呈批列表
  getFlowInstances (hide) {
    this.setState({ loading: true })
    if (!hide) {
      hide = message.loading('获取呈批列表', 120)
    }
    const flowKey = this.props.flowKey
    if (!this.props.caseDetail.id) { // 当案件id不存在时，不加载
      return false
    }
    this.resetAllForm()
    this.$get('/api/vendor/flowinstance', {
      caseid: this.props.caseDetail.id
    }).then(res => {
      if (res.status === 1) {
        this.initData(res.data.filter(li => li.flow_key === flowKey), hide)
      } else {
        hide()
        message.warning(res.message)
      }
    }).catch(() => {
      hide()
      this.setState({ loading: false })
    })
  }

  // 初始化数据
  initData (flowInstance, hide) {
    if (flowInstance.length) {
      this.formatFlowInstances(flowInstance, hide)
      this.$getFileList(this.props.caseDetail.id)
    } else {
      hide()
      this.setState({
        ready: true,
        loading: false
      }, () => {
        if (this.props.createDefault && this.props.creatable) {
          this.createApprowRequest()
        }
      })
    }
  }

  // 格式化多个实例，获取它的当前操作节点和历史操作
  formatFlowInstances (flowInstance, hide) {
    let list = _.cloneDeep(flowInstance)
    const ids = list.map(li => li.id)
    const map = {}
    list.forEach(li => {
      map[li.id] = li
      this.formRef[li.id] = React.createRef()
    })
    Promise.all([this.getHistorys(ids), this.getMultiCurrentStep(ids)])
      .then(async args => {
        hide()
        const historys = args[0]
        const currents = args[1]
        historys.forEach(h => {
          const o = map[h.instanceid]
          if (o) {
            h.history.sort((a, b) => a.create_datetime - b.create_datetime)
            o.history = h.history
          }
        })
        currents.forEach(c => {
          const o = map[c.instanceid]
          if (o) {
            o.currentStep = this.props.formatCurrentStepData(c.currentStep, o)
          }
        })
        const result = {
          instances: list,
          instancesMap: map,
          loading: false
        }
        this.isNoFirstNode(historys) // 判断是否不存在处于初始节点的呈批实例
        try {
          list = await this.props.setOtherDataInInstances(result)
        } catch (e) {
          console.warn('为实例添加其他数据失败')
          console.error(e)
        }
        this.setState(result)
      }).catch(e => {
        hide()
        this.setState({ loading: false })
        console.error(e)
        message.warning('获取呈批信息失败！')
      })
  }

  // 判断是否不存在处于初始节点的呈批实例
  isNoFirstNode (historys) {
    this.setState({
      noFirstNode: historys.length !== 0 && historys.every(li => li.history.length !== 0)
    })
  }

  // 获取一个实例的操作历史
  getApproveHistory (instanceid) {
    return this.$get('/api/vendor/flowinstance/action', {
      instanceid
    }).then(res => {
      if (res.status === 1) {
        const history = res.data
        history.forEach(h => {
          h.varsMap = this.getVarsMap(h.vars)
        })
        return {
          instanceid,
          history
        }
      }
      throw new Error(res.message)
    })
  }

  // 获取多个实例的操作信息
  getHistorys (instanceids = []) {
    return new Promise((resolve, reject) => {
      Promise.all(instanceids.map(id => this.getApproveHistory(id)))
        .then(args => {
          resolve(args)
        }).catch(e => reject(e))
    })
  }

  // 获取单个实例的当前操作节点
  getCurrentStep (instanceid) {
    return this.$get(`/api/vendor/flowinstance/${instanceid}`)
      .then(res => {
        if (res.status === 1) {
          const currentStep = res.data
          currentStep.varsMap = this.getVarsMap(res.data.vars)
          currentStep.actions.sort((a, b) => b.orderno - a.orderno)
          return {
            instanceid,
            currentStep
          }
        }
        throw new Error(res.message)
      })
  }

  // 获取多个实例的当前操作节点
  getMultiCurrentStep (instanceids = []) {
    return new Promise((resolve, reject) => {
      Promise.all(instanceids.map(id => this.getCurrentStep(id)))
        .then(args => {
          resolve(args)
        }).catch(e => reject(e))
    })
  }

  // 二次确认操作
  confirmAction (content, callback) {
    confirm({
      icon: <ExclamationCircleOutlined />,
      content,
      onOk () {
        callback()
      }
    })
  }

  // 发起呈批
  createApprow () {
    if (this.state.creating) {
      return false
    }
    this.setState({
      creating: true
    }, () => {
      try {
        this.props.setBizid()
          .then(bizid => this.createApprowRequest(bizid))
          .catch(e => {
            this.setState({
              creating: false
            })
            message.warning(e)
          })
      } catch (e) {
        this.setState({
          creating: false
        })
        console.warn('setBizid函数必须返回Promise对象')
      }
    })
  }

  getVarsMap (vars) {
    const map = {}
    vars.forEach(v => {
      map[v.key] = v
    })
    return map
  }

  //  强制重新请求提示
  requestAgainConfirm (content, onOk) {
    confirm({
      icon: <ExclamationCircleOutlined />,
      content,
      onOk,
      okText: '强制提交'
    })
  }

  // 创建呈批请求
  createApprowRequest (bizid, forcepassage) {
    const hide = message.loading('新增呈批中', 120)
    const data = { flow_name: this.state.flowName || this.props.flowName, caseid: this.props.caseDetail.id, bizid }
    if (forcepassage) {
      data.forcepassage = 1
    }
    this.$post('/api/vendor/flowinstance', data)
      .then(res => {
        hide()
        setTimeout(() => {
          this.setState({
            creating: false
          })
        }, 200)
        if (res.status === 1) {
          this.getFlowInstances()
        } else if (res.status === 2) {
          this.requestAgainConfirm(res.message, () => this.createApprowRequest(bizid, true))
        } else {
          message.warning(res.message)
        }
      }).catch(() => {
        hide()
        setTimeout(() => {
          this.setState({
            creating: false
          })
        }, 200)
      })
  }

  // 格式化日期
  formatDate (date) {
    if (date) {
      return moment(date * 1000).format('YYYY-MM-DD HH:mm')
    }
  }

  // 点击按钮，触发操作
  doAction (instance, action) {
    this.setState({
      currentAction: action
    }, () => {
      const c = this.formRef[instance.id].current
      if (['disagree', 'cancel'].indexOf(action.opt_add) !== -1) {
        this.dealAction(instance, { remark: c.getFieldValue(['remark']) })
      } else {
        c.submit()
      }
    })
  }

  // 进行操作
  async dealAction (instance, formData) {
    const action = this.state.currentAction
    if (['disagree', 'cancel'].indexOf(action.opt_add) === -1) { // 当操作为普通操作时，调用提交前处理函数
      try {
        this.setState({ doActioning: true })
        formData = await this.props.beforeSubmit(instance, formData, action)
        this.setState({ doActioning: false })
      } catch (e) {
        console.warn(e)
        this.setState({ doActioning: false })
        return message.warning('处理数据失败')
      }
    }
    this.setState({
      currentFlow: instance,
      currentFormData: formData
    }, () => {
      this.setState({
        nextOperatorId: ''
      })
      if (!action.next_operators || action.next_operator_type !== 'step_some') { // 当下一步没有操作者时，直接提交
        return this.toSubmitAction()
      }
      if (action.next_operators.length === 1) {
        this.setState({
          nextOperatorId: action.next_operators[0].id
        }, () => {
          this.toSubmitAction()
        })
      } else {
        this.setState({
          nextOperators: action.next_operators, // 下一步操作者选择列表
          nextOperatorSelectorVisible: true // 显示下一步操作者人员选择器
        })
      }
    })
  }

  // 从当前操作步骤中获取vars
  getVarsFromFormData () {
    const { currentFlow, currentFormData, currentAction } = this.state
    const vars = _.cloneDeep(currentFlow.currentStep.vars)
    if (['disagree', 'cancel'].indexOf(currentAction.opt_add) !== -1) {
      return []
    }
    vars.forEach(v => {
      // delete v.type
      v.value = (currentFormData.vars || {})[v.key] || ''
      delete v.options
    })
    return vars
  }

  // 提交操作请求
  async toSubmitAction (forcepassage) {
    const { currentFlow, currentAction, nextOperatorId, currentFormData } = this.state
    const hide = message.loading('提交中', 120)
    const data = {
      flowid: currentFlow.flowid,
      flow_instanceid: currentFlow.id,
      actionid: currentAction.id,
      action_name: currentAction.name,
      stepid: currentFlow.currentStep.stepid,
      remark: currentFormData.remark,
      operatorid_to: nextOperatorId,
      vars: this.getVarsFromFormData()
    }
    if (Object.prototype.hasOwnProperty.call(currentAction, 'level')) {
      data.level = currentAction.level
    }
    if (forcepassage) {
      data.forcepassage = 1
    }
    this.$post('/api/vendor/flowinstance/action', data).then(res => {
      setTimeout(() => {
        this.setState({ doActioning: false })
      }, 200)
      hide()
      if (res.status === 1) {
        this.props.updateUncompleteMessage()
        this.props.afterAction(currentFlow, currentAction) // 操作结束后，执行函数
        this.getFlowInstances()
        this.setState({
          currentAction: null,
          nextOperators: [],
          nextOperatorSelectorVisible: false,
          nextOperatorId: '',
          currentFlow: null,
          currentFormData: {}
        })
      } else if (res.status === 2) {
        this.requestAgainConfirm(res.message, () => this.toSubmitAction(true))
      } else {
        message.warning(res.message)
      }
    }).catch(() => {
      hide()
      setTimeout(() => {
        this.setState({ doActioning: false })
      }, 200)
    })
  }

  // 修改下一步操作人员id，并提交操作
  changeNextOperatorId (v) {
    this.setState({ nextOperatorId: v }, () => {
      this.toSubmitAction()
    })
  }

  readFile (id) {
    if (!id) {
      return message.warning('文书未生成完成')
    }
    this.$readerFileById(id, this.props.caseDetail.id)
  }

  // 新增多个呈批点击回调
  beforeMultiCreate () {
    if (this.props.multiCreateBeforeHandle) {
      try {
        this.props.multiCreateBeforeHandle(this.createApprow.bind(this))
      } catch (e) {
        message.warning('创建呈批失败')
      }
    } else {
      this.confirmAction(`您确定要${this.state.startTitle}吗？`, this.createApprow.bind(this))
    }
  }

  // 渲染历史列表
  renderHistoryList (instance) {
    return instance.history.map(h => {
      if (['disagree', 'cancel'].indexOf(h.opt_add) !== -1) {
        return this.renderHistory(h)
      }
      return this.props.renderHistory(h, this.renderHistory.bind(this), instance, this.renderDocument.bind(this, h))
    })
  }

  // 渲染历史操作状态
  renderOperateStatus (h) {
    if (['disagree', 'cancel'].indexOf(h.opt_add) !== -1) {
      return <span className={style.disagree}>{h.action_name}</span>
    }
    return <span>{h.action_name}</span>
  }

  // 渲染历史块
  renderHistory (h) {
    return (
      <div key={h.id}>
        <TitleLine title={h.step_name} operator={h.operator} time={this.formatDate(h.complete_datetime)} />
        <TextLine>
          <TextCell>操作：{h.action_name}</TextCell>
          <Split />
          <TextCell style={{ width: '65%' }}>{h.remark_alias || '备注'}：{h.remark || '无'}</TextCell>
        </TextLine>
        {this.renderDocument(h)}
      </div>
    )
  }

  renderDocument (h) {
    const docs = _.cloneDeep(h.vars.filter(l => l.type === '文书'))
    if (!docs.length) {
      return null
    }
    return (
      <>
        <TitleLine title='文书列表' />
        {this.renderDocumentList(h, docs)}
      </>
    )
  }

  // 生成历史vars中的文书列表
  renderDocumentList (h, docs) {
    const arr = []
    let i = 0
    while (docs.length) {
      i++
      const three = docs.splice(0, 3)
      arr.push(this.renderDocumentLine(three, i))
    }
    return arr
  }

  // 生成历史文书行
  renderDocumentLine (arr, index) {
    const list = []
    arr.filter(li => li.value).forEach((li, i) => {
      list.push(<TextCell key={li.title}><DocLink title={li.title} src={li.value} onClick={() => this.readFile(li.value)} /></TextCell>)
      if (i < 2) {
        list.push(<Split key={index + '-' + i} />)
      }
    })
    return (
      <TextLine key={index}>
        {list}
      </TextLine>
    )
  }

  // 渲染当前操作步骤
  renderCurrentStep (instance) {
    if (this.state.loading) {
      return <div style={{ padding: '24px' }}><Skeleton active /></div>
    }
    const { currentStep: c } = instance
    let data = {}
    if (!c.stepid) { // 呈批已完成
      return null
    }
    const isOperate = c.operators.some(o => o.id === this.props.userInfo.employeeid)
    if (!isOperate) { // 判断当前操作者是否有操作权限
      return this.noAuthorityrCurrentStep(instance)
    }
    if (this.props.initialCurrentStepFormData) {
      data = this.props.initialCurrentStepFormData(instance)
    }
    const formRef = this.formRef[instance.id]
    return (
      <Form name={instance.currentStep.stepid} initialValues={data} ref={formRef} onFinish={data => this.dealAction(instance, data)} onValuesChange={(changedValues, allValues) => this.props.formValueChange(changedValues, allValues, instance, formRef)}>
        {this.renderVars(instance)}
        {c.step_name ? <TitleLine title={c.step_name} /> : null}
        {this.props.renderCurrentStepLineTop(formRef, instance, this.renderDefaultCurrentStepText.bind(this, instance))}
        {this.renderCurrentStepOperateBlock(formRef, instance)}
      </Form>
    )
  }

  // 渲染没有操作权限者看到的当前节点提示
  noAuthorityrCurrentStep (instance) {
    const { currentStep: c } = instance
    const operatorNames = instance.currentStep.operators.map(li => li.name).join('、')
    return (
      <div>
        {c.step_name ? <TitleLine title={c.step_name} /> : null}
        <TextLine>
          <TextCell>操作者：{operatorNames}</TextCell>
          <Split />
          <TextCell>未操作</TextCell>
        </TextLine>
      </div>
    )
  }

  // 渲染vars参数
  renderVars (instance) {
    return instance.currentStep.vars.map(li => <Item key={li.title} noStyle name={['vars', li.key]}><span /></Item>)
  }

  // 渲染当前步骤默认文本
  renderDefaultCurrentStepText (c) {
    return (
      <TextLine>
        <TextCell>操作者：{this.props.userInfo.realname}</TextCell>
      </TextLine>
    )
  }

  // 渲染当前步骤的操作块
  renderCurrentStepOperateBlock (formRef, instance) {
    return (
      <div>
        <Footer>
          {this.props.renderCurrentStepLineBottom(formRef, instance)}
          {this.renderCurrentStepDefaultOperate(instance)}
        </Footer>
      </div>
    )
  }

  // 渲染当前步骤的默认操作框
  renderCurrentStepDefaultOperate (instance) {
    const { currentStep } = instance
    return (
      <Line>
        <Cell style={{ width: '65%' }}>
          <Item label={currentStep.remark_alias || '备注'} name='remark' style={{ marginBottom: 0 }}>
            <Input placeholder='请输入备注' className={style.full} />
          </Item>
        </Cell>
        <Split />
        <Cell style={{ textAlign: 'right' }}>
          <OperateBtns instance={instance} formRef={this.formRef[instance.id]} callBack={(action) => this.doAction(instance, action)} disable={this.state.doActioning} refreshApprove={() => this.getData()} />
        </Cell>
      </Line>
    )
  }

  // 渲染呈批
  renderApprove () {
    return (
      <div>
        <NextOperatorSelector visible={this.state.nextOperatorSelectorVisible} list={this.state.nextOperators} hide={() => this.setState({ nextOperatorSelectorVisible: false })} changeOperatorId={v => this.changeNextOperatorId(v)} />
        {
          this.state.instances.map(instance => {
            return (
              <ApproveBlock key={instance.id}>
                <Header title={instance.flow_name} />
                {this.props.renderFlowOtherInfo && this.props.renderFlowOtherInfo(instance)}
                {this.renderHistoryList(instance)}
                {this.renderCurrentStep(instance)}
              </ApproveBlock>
            )
          })
        }
        {this.props.multiply && this.state.noFirstNode && this.props.creatable ? this.renderMultiplyCreateButton() : null}
      </div>
    )
  }

  renderCreateApprove () {
    return (
      <ApproveBlock>
        <Header title={this.state.flowName || this.props.flowName}>
          <Button type='primary' disabled={this.state.creating} loading={this.state.creating} onClick={() => this.confirmAction(`您确定要${this.state.startTitle}吗？`, this.createApprow.bind(this))}>{this.state.startTitle}</Button>
        </Header>
      </ApproveBlock>
    )
  }

  renderMultiplyCreateButton () {
    const btnName = this.props.multiCreateButtonText
    return (
      <div className={style['add-button']}>
        <Button type='dashed' disabled={this.state.creating} block onClick={() => this.beforeMultiCreate()}>+ {btnName}</Button>
      </div>
    )
  }

  componentDidUpdate (prev) {
    if (!prev.caseDetail.id && this.props.caseDetail.id) {
      this.getData()
    }
  }

  componentDidMount () {
    this.getData()
  }

  render () {
    // if (this.state.loading) {
    //   return <Skeleton active />
    // }
    if (this.state.instances.length) {
      return this.renderApprove()
    }
    if (this.props.creatable && this.state.ready && !this.props.createDefault) {
      return this.renderCreateApprove()
    }
    if (!this.props.creatable && this.state.ready) {
      return <Alert message='无操作权限' type='warning' showIcon />
    }
    return <span />
  }
}

ApproveList.proptypes = {
  caseDetail: PropTypes.object,
  flowKey: PropTypes.string,
  flowName: PropTypes.string,
  creatable: PropTypes.bool,
  setBizid: PropTypes.func,
  renderHistory: PropTypes.func,
  renderCurrentStepLineTop: PropTypes.func,
  renderCurrentStepLineBottom: PropTypes.func,
  beforeSubmit: PropTypes.func,
  initialCurrentStepFormData: PropTypes.func,
  setOtherDataInInstances: PropTypes.func,
  afterAction: PropTypes.func,
  formValueChange: PropTypes.func,
  createDefault: PropTypes.bool,
  multiply: PropTypes.bool,
  multiCreateButtonText: PropTypes.string,
  multiCreateBeforeHandle: PropTypes.func,
  renderFlowOtherInfo: PropTypes.func,
  formatCurrentStepData: PropTypes.func
}

ApproveList.defaultProps = {
  caseDetail: {},
  flowKey: '',
  flowName: '',
  creatable: true,
  setBizid: () => Promise.resolve(), // 创建呈批时，可以为呈批实例设置bizid
  renderHistory: (h, renderFn, instance, renderDoc) => renderFn(h),
  renderCurrentStepLineTop: (formRef, instance, renderFn) => renderFn(), // 渲染当前操作步骤线上部分
  renderCurrentStepLineBottom: (formRef, instance) => {}, // 渲染当前操作步骤线下部分
  beforeSubmit: (instance, data, action) => Promise.resolve(data), // 提交前，对数据进行操作
  initialCurrentStepFormData: null, // 设置表单初始化数据
  setOtherDataInInstances: data => Promise.resolve(data), // 为实例列表中的实例设置其他数据
  afterAction: (currentInstance, currentAction) => {}, // 操作结束后回调
  formValueChange: (changedValues, allValues, instances, formRef) => {}, // 当前步骤form表单值改变时回调
  createDefault: false, // 当呈批为空时，是否默认创建一个呈批
  multiply: false, // 是否准许创建多个呈批
  multiCreateButtonText: '添加呈批',
  multiCreateBeforeHandle: null, // 新增多个呈批，创建前回调
  renderFlowOtherInfo: null, // 渲染呈批的其他信息
  formatCurrentStepData: (d, instance) => d // 格式化当前步骤数据
}

const mapState = mapStateToProps(function (state) {
  return {
    userInfo: state.basic.userInfo
  }
})

const mapDispatch = mapDispatchToProps(function (dispatch) {
  return {
    updateUncompleteMessage: () => dispatch(updateUncompleteMessage(dispatch))
  }
})

export default connect(mapState, mapDispatch)(ApproveList)
